package com.googlecode.lohr.parser.combinators.matcher.common;


import com.googlecode.lohr.parser.combinators.MatchError;
import com.googlecode.lohr.parser.combinators.matcher.MatchContext;
import com.googlecode.lohr.parser.combinators.matcher.MatchListener;
import com.googlecode.lohr.parser.combinators.matcher.Matcher;
import com.googlecode.lohr.parser.combinators.node.AbstractNode;
import com.googlecode.lohr.parser.combinators.node.StringNode;

public class DecimalMatcher
extends Matcher
{
	static final private IntegerMatcher __integerMatcher= new IntegerMatcher();
	//decimal ::= ([sign] ((digits "." {digits}) | ("." digits) | digits)) 
	@Override
	public void match(final MatchContext ctx, final int start) 
	{
		final String input= ctx.getInput();
		final Matcher targetMatcher= this;
		ctx.doMatch(__integerMatcher, start, new MatchListener() {
			AbstractNode _match;
			@Override
			public void onMatchFound(AbstractNode node) {
				_match= node;
			}
			
			@Override
			public void onMatchComplete(MatchError matchError) {
				if (_match == null) {
					if ('.' == input.charAt(start))
					{
						ctx.doMatch(__integerMatcher, start+1, new MatchListener() {
							AbstractNode _fraction;
							@Override
							public void onMatchFound(AbstractNode node) {
								_fraction= node;
							}
							@Override
							public void onMatchComplete(MatchError matchError) {
								if (_fraction == null) {
									ctx.matchComplete(targetMatcher, start, new MatchError("Expected a double", start));
									return;
								}
								
								String txt= input.substring(start, _fraction.getEnd());
								AbstractNode decimal= new StringNode(targetMatcher, start, _fraction.getEnd(), txt);
								ctx.matchFound(targetMatcher, start, decimal);
								ctx.matchComplete(targetMatcher, start);
							}
						});
					}
					else
						ctx.matchError(targetMatcher, start, new MatchError("Expected a double", start));
				}
				else {
					if ('.' == input.charAt(_match.getEnd())) 
					{
						ctx.doMatch(__integerMatcher, _match.getEnd()+1, new MatchListener() {
							AbstractNode _fraction;
							@Override
							public void onMatchFound(AbstractNode node) {
								_fraction= node;
							}
							@Override
							public void onMatchComplete(MatchError matchError) {
								int end= _match.getEnd()+1;
								if (_fraction != null)
									end= _fraction.getEnd();
								String txt= input.substring(start, end);
								AbstractNode decimal= new StringNode(targetMatcher, start, end, txt);
								ctx.matchFound(targetMatcher, start, decimal);
								ctx.matchComplete(targetMatcher, start);
							}
						});
					}
					else {
						ctx.matchFound(targetMatcher, start, _match);
						ctx.matchComplete(targetMatcher, start);
					}
				}
			}
		});
	}
	
	@Override
	public String getLabel()
	{
		return "decimal";
	}
}
